#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./LinkedString.h"

// 初始化
Status InitString(LinkedString *pStr) {
    pStr->head = pStr->tail = NULL;
    pStr->length = 0;
    return OK;
}

// 赋值
Status StrAssign(LinkedString *pStr, char *insertedStr) {
    // 将字符串 insertedStr 插入到块链 pStr 中
    // 块链的长度, 和初始化时的字符串相同
    int len = strlen(insertedStr);
    if(!len) {
        return ERROR;
    }
    pStr->length = len;

    // 初始化后结点的个数
    int nodeCount = len / CHARSIZE;
    if(len % CHARSIZE) {
        // 最后一个结点是否满了, 如果总长度不是每个结点所储存的字符个数的整倍数, 说明最后一个结点不满, 则需要加1; 如果是整倍数, 则说明 len/CHARSIZE 刚好
        nodeCount++;
    }

    int i, k;
    Node *pTmp = NULL;
    for (i = 0; i < nodeCount; i++) {
        pTmp = (Node*)malloc(sizeof(Node));
        if(!pTmp) {
            // 申请结点失败
            return ERROR;
        }

        for (k = 0; k < CHARSIZE && *insertedStr; k++) {
            *(pTmp->data+k) = *insertedStr++;
        }

        // 第一次时初始化头指针
        if(i == 0) {
            pStr->head = pStr->tail = pTmp;
        } else {
            // 不是第一次, 说明前面已经有结点了, 这时只移动尾指针
            pStr->tail->next = pTmp;
            pStr->tail = pTmp;
        }
        pStr->tail->next = NULL;

        // 将最后一个结点的不满的部分用'#'填充
        if(!*insertedStr) {
            for(; k < CHARSIZE; k++) {
                *(pStr->tail->data + k) = STUFF;
            }
        }
    }
    return OK;
}

// 是否为空
Status IsStrEmpty(LinkedString str) {
    if (str.length == 0) {
        return TRUE;
    }
    return FALSE;
}

// 取长度
unsigned int StrLength(LinkedString str) {
    return str.length;
}

// 复制
Status StrCopy(LinkedString *to, LinkedString from) {
    // // 1. 字符串的长度
    // to->length = from.length;
    // // 2. 结点的个数
    // unsigned int nodeSize = (from.tail - from.head) / sizeof(Node) + 1;

    char *str = NULL;
    int flag;
    if (!ToChars(from, &str)) {
        return ERROR;
    }
    flag = StrAssign(to, str);
    if (!flag) {
        return ERROR;
    }
    // 释放掉str
    free(str);
    return OK;
}

// 串的转换: 串的转换操作。将串S的内容转换为字符串，将串S中的字符拷贝到cstr。成功返回1，否则返回0
// 注意, 传入的 toStr 一定要使用free释放
Status ToChars(LinkedString str, char **toStr) {
    Node *p = str.head;
    // 申请 str.length + 1 个 char 的储存空间
    char *locateStrp = (char*)malloc((str.length + 1) * sizeof(char));
    if(!locateStrp || !str.length) {
        return ERROR;
    }
    int i = 0;
    while(p) {

        char *current = p->data;
        for (i = 0; i < CHARSIZE && current[i] != STUFF; i++) {
            *locateStrp = current[i];
            locateStrp++;
        }

        // 向后移动一个基本单元, 这里的基本单元是一个 Node 的内存大小
        // p++;
        // 或者
        p = p->next;
    }
    *locateStrp = '\0';
    *toStr = locateStrp - str.length * sizeof(char);
    return OK;
}

// 串的比较
// 串的比较操作。若str1的值大于str2，则返回正值；若str1的值等于str2，则返回0；若str1的值小于str2，则返回负值
Status StrCompare(LinkedString str1, LinkedString str2) {
    char *pStr1, *pStr2, *fpStr1, *fpStr2;
    int flag = 0;
    if (!ToChars(str1, &pStr1)) {
        return ERROR;
    }
    if (!ToChars(str2, &pStr2)) {
        free(pStr1);
        return ERROR;
    }

    // 保存下来, 将来要释放掉
    fpStr1 = pStr1;
    fpStr2 = pStr2;
    for (; *pStr1 != '\0' && *pStr2 != '\0';) {
        if (*pStr1 == *pStr2) {
            pStr1++;
            pStr2++;
        } else {
            flag = *pStr1 - *pStr2;
            break;
        }
    }
    // 注意, 一定要释放掉str
    free(fpStr1);
    free(fpStr2);
    if (*pStr1 != '\0' || *pStr2 != '\0') {
        return str1.length - str2.length;
    } else {
        return flag;
    }
}

// 串的链接
// 将串 str2 连接到 第一个参数上去
Status StrConcat(LinkedString *pStr, LinkedString str2) {
    int flag1, flag2;
    LinkedString s1, s2;
    InitString(&s1);
    InitString(&s2);
    flag1 = StrCopy(&s1, *pStr);
    flag2 = StrCopy(&s2, str2);
    if (!flag1 || !flag2) {
        return ERROR;
    }
    // 清空老的
    ClearString(pStr);
    pStr->head = s1.head;
    pStr->tail = s2.tail;
    s1.tail->next = s2.head;
    pStr->length = s1.length + s2.length;
    return OK;
}

// 串的插入
Status StrInsert(LinkedString *pStr, int pos, LinkedString insertedStr) {
    // 插入的合法位置为 1 - length+1
    if (pos < 1 || pos > pStr->length + 1) {
        // 位置不合法
        return ERROR;
    }
    // 将要插入的块链转换成字符串
    char *toStr = NULL;
    if (!ToChars(*pStr, &toStr)) {
        return ERROR;
    }
    char *toInsStr = NULL;
    if (!ToChars(insertedStr, &toInsStr)) {
        free(toStr);
        return ERROR;
    }

    // 保存我们转换后的新字符串
    // 为什么要加1, 因为要在最后保存字符串的结束符\0
    // 添加之后的长度
    int insertedLength = strlen(toInsStr);
    int afterLength = strlen(toStr) + insertedLength + 1;
    toStr = (char*)realloc(toStr, sizeof(char) * afterLength);
    int current = pStr->length;
    // 位置是pos, 在数组中的下标是pos-1
    while(current >= pos) {
        toStr[current + insertedLength - 1] = *(toStr + current - 1);
        current--;
    }
    // 再把要加入的添加进去
    int i;
    for (i = 0; i < insertedLength; i++) {
        toStr[pos + i - 1] = *(toInsStr + i);
    }
    // 添加之后的字符串
    toStr[afterLength-1] = '\0';

    ClearString(pStr);
    int flag = StrAssign(pStr, toStr);

    // 善后操作, 释放掉ToChars函数返回的字符串
    free(toStr);
    free(toInsStr);
    return flag;
}

// 串的删除
Status StrDelete(LinkedString *pStr, int pos, int len) {
    // 判断删除的位置是否合法
    if(pos < 1 || pos > pStr->length || len < 0) {
        return ERROR;
    }

    char *toStr = NULL;
    // 转换成 字符串格式
    if (!ToChars(*pStr, &toStr)) {
        // 转换失败
        return ERROR;
    }

    if (pos + len - 1 > pStr->length) {
        // 要删除的位置加上删除的长度后, 超过了字符串的长度, 则默认删除要删除的位置到字符串的末尾
        len = pStr->length - pos + 1;
        *(toStr + pos) = '\0';
    } else {
        int i;
        for (i = pos + len - 1; i <= (int)strlen(toStr); i++) {
            *(toStr + i - len) = *(toStr + i);
        }
    }
    ClearString(pStr);
    int flag = StrAssign(pStr, toStr);
    // 最后释放掉ToChars申请的内存空间
    free(toStr);
    return flag;
}

// 取子串
Status SubString(LinkedString str, int pos, int len, LinkedString *subStr) {
    // 1. 判断 pos, len 是否符合合适
    if (pos < 1 || pos > str.length || len < 0 || len > str.length-pos+1) {
        return ERROR;
    }
    // 申请新的空间
    char *nStr = (char*)malloc((len + 1) * sizeof(char));
    if (!nStr) {
        // 申请失败
        return ERROR;
    }

    char *toStr = NULL;
    if (!ToChars(str, &toStr)) {
        // 转化为字符串失败
        return ERROR;
    }

    int i;
    for (i = 0; i < len; i++) {
        *(nStr + i) = *(toStr + pos - 1 + i);
    }
    *(nStr + len) = '\0';

    if (!StrAssign(subStr, nStr)) {
        return ERROR;
    }

    // 释放掉申请的内存空间
    free(toStr);
    free(nStr);
    return OK;
}

// 取子串第二种写法
// 用subStr返回串str的第pos个字符起长度为len的子串
Status SubString02(LinkedString str, int pos, int len, LinkedString *subStr) {
    char *toStr = NULL;
    // 1. 判断 pos, len 是否符合合适
    if (pos < 1 || pos > str.length || len < 0 || len > str.length-pos+1) {
        return ERROR;
    }
    // 使用ToChars, 之后一定要记得释放掉
    if (!ToChars(str, &toStr)) {
        return ERROR;
    }
    toStr[pos + len + 1] = '\0';
    if (!StrAssign(subStr, toStr+pos)) {
        return ERROR;
    }

    // 释放掉ToChars函数申请的空间
    free(toStr);
    return OK;
}

// 清空串, 将串的空间释放掉
Status ClearString(LinkedString *pStr) {
    printf("%d\n%d\n", pStr->tail - pStr->head, (pStr->tail - pStr->head) / sizeof(Node));
    Node *p = NULL;
    while(pStr->head && pStr->head <= pStr->tail) {
        p = pStr->head;
        pStr->head = p->next;
        free(p);
    }
    pStr->head = pStr->tail = NULL;
    pStr->length = 0;
    return OK;
}

void Print(LinkedString s) {
    Node *current = s.head;
    int i;
    while(current != NULL) {
        for (i = 0; i < CHARSIZE; i++) {
            if (*(current->data + i) == STUFF) {
                break;
            }
            printf("%c", *(current->data + i));
        }
        current = current->next;
    }
    printf("\n");
}

int main() {
    LinkedString ls;
    InitString(&ls);
    
    printf("%d\n", sizeof(Node));
    // 赋值
    char *str1 = "welcome to chinal";
    StrAssign(&ls, str1);

    // 复制
    LinkedString copiedStr;
    StrCopy(&copiedStr, ls);

    StrCompare(ls, copiedStr);


    LinkedString subStr;
    SubString(ls, 1, 7, &subStr);

    StrDelete(&subStr, 3, 2);

    StrInsert(&subStr, 4, ls);
    Print(subStr);
    Print(ls);
    ClearString(&ls);
    return 0;
}